# pylint: disable=wildcard-import,unused-wildcard-import
#pylint: disable=missing-docstring
#pylint: disable=no-init
#pylint: disable=too-few-public-methods
import datetime
from decimal import Decimal
from collections import OrderedDict

from nmea import TalkerSentence


def timestamp(s):
    '''
    Converts "hhmmss[.ss]" text to a
    datetime.time object
    '''
    ms_s = s[6:]
    ms = ms_s and int(float(ms_s) * 1000000) or 0

    t = datetime.time(
        hour=int(s[0:2]),
        minute=int(s[2:4]),
        second=int(s[4:6]),
        microsecond=ms)
    return t


def datestamp(s):
    '''
    Converts "DDMMYY" text to a
    datetime.datetime
    '''
    try:
        ans = datetime.datetime.strptime(s, '%d%m%y').date()
    except Exception as err:
        raise err
    return ans


class HDT(TalkerSentence):
    """[$HEHDT]
        Format="$HEHDT,%.1f,T"
        Count=1
        0=GyroHeading
    """
    fields = (
        ("GyroHeading", "GyroHeading", Decimal),
        ("True", "true")
    )

    def extract(self):
        ans = {
            'Type': {
                'TalkID': self.talker,
                'SentenceType': self.sentence_type,
            },
            'Data': {
                'GyroHeading': self.GyroHeading
            }
        }
        return ans


class RMC(TalkerSentence):
    """[$GPRMC]
        Format="$GPRMC,%02d%02d%02d.00,A,%s,%s,%.1f,%.1f,%02d%02d%02d,,A"
        Count=10
        0=GPSHour
        1=GPSMinute
        2=GPSSecond
        3=GPSLatitude
        4=GPSLongitude
        5=GPSSpeed,1.944
        6=GPSCourse
        7=GPSDay
        8=GPSMonth
        9=GPSYearShort

    """
    fields = (
        ("Timestamp", "Timestamp", timestamp),
        ('Constant A 1', 'constant_A_1'),
        ("GPSLatitude", "GPSLatitude"),
        ("GPSLongitude", "GPSLongitude"),
        ("GPSSpeed", "GPSSpeed", float),
        ("GPSCourse", "GPSCourse", float),
        ("Datestamp", "Datestamp", datestamp),
        ("Empty Field", "empty"),
        ("Constant A 2", "constant_A_2"),
    )

    def extract(self):
        data = {
            'GPSHour': self.Timestamp.hour,
            'GPSMinute': self.Timestamp.minute,
            'GPSSecond': self.Timestamp.second,
            'GPSLatitude': self.GPSLatitude,
            'GPSLongitude': self.GPSLongitude,
            'GPSSpeed': self.GPSSpeed,
            'GPSCourse': self.GPSCourse,
            'GPSDay': self.Datestamp.day,
            'GPSMonth': self.Datestamp.month,
            'GPSYearShort': self.Datestamp.year
        }
        ans = {
            'Type': {
                'TalkID': self.talker,
                'SentenceType': self.sentence_type,
            },
            'Data': OrderedDict(data)
        }
        return ans


class VBW(TalkerSentence):
    """[$VDVBW]
        Format="$VDVBW,%.2f,%.2f,A,%.2f,%.2f,A,%.2f,A,%.2f,A"
        Count=6
        0=LogWTLongitudinal,1.944  (1.944只是内部的系数换算，输出的数据与实际一致)
        1=LogWTBow,1.944
        2=LogBTLongitudinal,1.944
        3=LogBTBow,1.944
        4=LogWTStern,1.944
        5=LogBTStern,1.944
    """
    fields = (
        ("LogWTLongitudinal", "LogWTLongitudinal", Decimal),
        ("LogWTBow", "LogWTBow", Decimal),
        ('Status 1', 'Constant_A_1'),
        ("LogBTLongitudinal", "LogBTLongitudinal"),
        ("LogBTBow", "LogBTBow", Decimal),
        ('Status 2', 'Constant_A_2'),
        ("TLogWTStern", "LogWTStern", Decimal),
        ('Status 3', 'Constant_A_3'),
        ("LogBTSterny", "LogBTStern", Decimal),
        ('Status 4', 'Constant_A_4')
    )

    def extract(self):
        ans = {
            'Type': {
                'TalkID': self.talker,
                'SentenceType': self.sentence_type,
            },
            'Data': OrderedDict()
        }
        ans['Data']['LogWTLongitudinal'] = self.LogWTLongitudinal
        ans['Data']['LogWTBow'] = self.LogWTBow
        ans['Data']['LogBTLongitudinal'] = self.LogBTLongitudinal
        ans['Data']['LogBTBow'] = self.LogBTBow
        ans['Data']['LogWTStern'] = self.LogWTStern
        ans['Data']['LogBTStern'] = self.LogBTStern
        return ans


class RSA(TalkerSentence):
    """[$IIRSA]
        Format="$IIRSA,G,%f,,RUDDER1,G,%f,,RUDDER2"
        Count=2
        0=RudderReplyPS
        1=RudderReplySB
    """
    fields = (
        ("G1", "G1"),
        ("RudderReplyPS", "RudderReplyPS", Decimal),
        ("Blank1", "Blank1"),
        ("RUDDER1", "RUDDER1"),
        ("G2", "G2"),
        ("RudderReplySB", "RudderReplySB", Decimal),
        ("Blank2", "Blank2"),
        ("RUDDER2", "RUDDER2")
    )

    def extract(self):
        ans = {
            'Type': {
                'TalkID': self.talker,
                'SentenceType': self.sentence_type,
            },
            'Data': OrderedDict()
        }
        ans['Data']['RudderReplyPS'] = self.RudderReplyPS
        ans['Data']['RudderReplySB'] = self.RudderReplySB
        return ans


class PCU(TalkerSentence):
    """[$AAPCU]  暂定,AA,PCU都可以根据需要修改
        Format="$AAPCU,%.1f, %.2f, %.3f"
        Count=3
        0=pressure   单位:mbar
        1=CurrentDirection  精确到0.1度
        2=CurrentSpeed   暂定单位为m/s,可以根据实际换算
    """

    fields = (
        ("pressure", "pressure", Decimal),
        ("CurrentDirection", "CurrentDirection", Decimal),
        ("CurrentSpeed", "CurrentSpeed", Decimal)
    )

    def extract(self):
        data = {
            'pressure': self.pressure,
            'CurrentDirection': self.CurrentDirection,
            'CurrentSpeed': self.CurrentSpeed
        }
        ans = {
            'Type': {
                'TalkID': self.talker,
                'SentenceType': self.sentence_type,
            },
            'Data': OrderedDict(data)
        }
        return ans


class MWD(TalkerSentence):
    """[$WIMWD]
        Format="$WIMWD,%.1f,T,,M,%.2f,N,,M"
        Count=2
        0=WindDirection
        1=WindSpeed,1.944
    """
    fields = (
        ("WindDirection", "WindDirection", Decimal),
        ("T", "T"),
        ("Blank1", "Blank1"),
        ("M1", "M1"),
        ("WindSpeed", "WindSpeed", Decimal),
        ("N", "N"),
        ("Blank2", "Blank2"),
        ("M2", "M2"),
    )

    def extract(self):
        ans = {
            'Type': {
                'TalkID': self.talker,
                'SentenceType': self.sentence_type,
            },
            'Data': {
                'WindDirection': self.WindDirection,
                'WindSpeed': self.WindSpeed
            }
        }
        return ans


class MWV(TalkerSentence):
    """[$WIMWV]
        Format="$WIMWV,%.1f,R,%.2f,M,A"
        Count=2
        0=WindRelDirection
        1=WindRelSpeed
    """
    fields = (
        # in relation to vessel's centerline
        ("WindRelDirection", "WindRelDirection", Decimal),
        ("R", "R"),  # relative (R)/true(T)
        ("WindRelSpeed", "WindRelSpeed", Decimal),
        ("M", "M"),  # K/M/N
        ("A", "A"),
    )

    def extract(self):
        data = {
            'WindRelDirection': self.WindRelDirection,
            'WindRelSpeed': self.WindRelSpeed
        }
        ans = {
            'Type': {
                'TalkID': self.talker,
                'SentenceType': self.sentence_type,
            },
            'Data': OrderedDict(data)
        }
        return ans


class DBT(TalkerSentence):
    """[$SDDBT]
        Format="$SDDBT,%.1f,f,%.1f,M,%.1f,F"
        Count=3
        0=SounderDepth,3.29
        1=SounderDepth
        2=SounderDepth,0.547
    """
    fields = (
        ("SounderDepth0", "SounderDepth0", Decimal),
        ("f", "f"),
        ("SounderDepth1", "SounderDepth1", Decimal),
        ("M", "M"),
        ("SounderDepth2", "SounderDepth2", Decimal),
        ("F", "F"),
    )

    def extract(self):
        data = {
            'SounderDepth0': self.SounderDepth0,
            'SounderDepth1': self.SounderDepth1,
            'SounderDepth2': self.SounderDepth2
        }
        ans = {
            'Type': {
                'TalkID': self.talker,
                'SentenceType': self.sentence_type,
            },
            'Data': OrderedDict(data)
        }
        return ans


class VLW(TalkerSentence):
    """[$VDVLW]
        Format="$VDVLW,%.2f,N,%.2f,N,%.2f,N,%.2f,N"
        Count=4
        0=LogDistance,0.00053
        1=LogDistance,0.00053
        2=LogDistance,0.00053
        3=LogDistance,0.00053
    """
    fields = (
        ('LogDistance', 'LogDistance0', Decimal),
        ('Nautical Miles', 'nm1'),
        ('LogDistance', 'LogDistance1', Decimal),
        ('Nautical Miles', 'nm1'),
        ('LogDistance', 'LogDistance2', Decimal),
        ('Nautical Miles', 'nm1'),
        ('LogDistance', 'LogDistance3', Decimal),
        ('Nautical Miles', 'nm1')
    )

    def extract(self):
        ans = {
            'Type': {
                'TalkID': self.talker,
                'SentenceType': self.sentence_type
            },
            'Data': OrderedDict()
        }
        ans['Data']['LogDistance0'] = self.LogDistance0
        ans['Data']['LogDistance1'] = self.LogDistance1
        ans['Data']['LogDistance2'] = self.LogDistance2
        ans['Data']['LogDistance3'] = self.LogDistance3
        return ans


class ROT(TalkerSentence):
    """[$HEROT]
        Format="$HEROT,%.1f,A"
        Count=1
        0=GyroRateOfTurn
    """
    fields = (
        # - indicates bow turn to port
        ("GyroRateOfTurn", "GyroRateOfTurn", float),
        ('Status', 'status'),  # contains the 'A' or 'B' flag
    )

    def extract(self):
        ans = {
            'Type': {
                'TalkID': self.talker,
                'SentenceType': self.sentence_type,
            },
            'Data': OrderedDict({
                'GyroRateOfTurn': self.GyroRateOfTurn
            })
        }
        return ans


class RPM(TalkerSentence):
    """[$IIRPM]
        Format="$IIRPM,T,%f,R,PSPROPELLER,T,%f,R,SBPROPELLER"
        Count=2
        0=PropellerRPMPS
        1=PropellerRPMSB

    """

    fields = (
        ("T 1", "T_1"),
        ("PropellerRPMPS", "PropellerRPMPS", float),
        ("R 1", "R_1"),
        ("PSPROPELLER", "PSPROPELLER"),
        ("T 2", "T_2"),
        ('PropellerRPMSB', 'PropellerRPMSB', float),
        ("R 2", "R_2"),
        ('SBPROPELLER', 'SBPROPELLER')
    )

    def extract(self):
        ans = {
            'Type': {
                'TalkID': self.talker,
                'SentenceType': self.sentence_type,
            },
            'Data': OrderedDict({
                'PropellerRPMPS': self.PropellerRPMPS,
                'PropellerRPMSB': self.PropellerRPMSB
            })
        }
        return ans


class TTM(TalkerSentence):
    """
    [$RATTM] 1
        Format="$RATTM,%02d,%.3f,%.2f,T,,,,,,N,,Q,,,"
    [$RATTM] 2
        Format="$RATTM,%02d,%.3f,%.2f,T,%.2f,%.2f,T,%.3f,%.2f,N,,T,,,"
    TTM语句也是标准格式并能被真机接受,比如第三方电子海图主机,具体请参见NMEA手册标准定义
    """
    fields = (
        ("Target Number", "TargetNumber", int),
        ("Target Distance", "TargetDistance", Decimal),
        ("Bearing from Own Ship", "Bearing", Decimal),
        ("Bearing Reference", "BearRef"),
        ("Target Speed", "TargetSpeed", Decimal),
        ("Target Course over Ground", "TargetCourse", Decimal),
        ("Course Units", "CourseUnit"),
        ("Distance of CPA", "DistanceCPA", Decimal),
        ("Time until CPA", "TimeCPA", Decimal),
        ("Distance Units", "DistUnit"),
        ("Target Name", "TargetName"),
        ("Target Status", "TargetStatus"),
        ("Target Reference", "TargetReference"),
        ("Timestamp (UTC)", "timestamp", timestamp),
        ("Acquisition Type", "Acquisition")
    )

    def extract(self):
        ans = {
            'Type': {
                'TalkID': self.talker,
                'SentenceType': self.sentence_type,
            },
            'Data': OrderedDict({
                'TargetNumber': self.TargetNumber,
                'TargetDistance': self.TargetNumber,
                'Bearing': self.Bearing,
                'TargetSpeed': self.TargetSpeed,
                'TargetCourse': self.TargetCourse,
                'DistanceCPA': self.DistanceCPA,
                'TimeCPA': self.TimeCPA
            })
        }
        return ans


class VDM(TalkerSentence):
    """好难找，NMEA 的文档里没有，还是翻墙才找到的格式说明
        !AIVDM,1,1,,B,177KQJ5000G?tO`K>RA1wUbN0TKH,0*5C

            Field 1, !AIVDM, identifies this as an AIVDM packet.

            Field 2 (1 in this example) is the count of fragments in the currently accumulating message.

            Field 3 (1 in this example) is the fragment number of this sentence.

            Field 4 (empty in this example) is a sequential message ID for multi-sentence messages.

            Field 5 (B in this example) is a radio channel code.

            Field 6 (177KQJ5000G?tO`K>RA1wUbN0TKH in this example) is the data payload.

            Field 7 (0) is the number of fill bits requires to pad the data payload to a 6 bit boundary, ranging from 0 to 5.
    """

    fields = (
        ("Count of Fragments", "FragmentCnt", int),
        ("Fragment Number", "FragmentNum", int),
        ("Sequential Message ID", "SeqID", int),
        ("Radio Channel Code", "RadioChannelCode"),
        ("Data Payload", "Payload"),
        ("Number Of Fill Bits", "FillBits")
    )

    def extract(self):
        ans = {
            'Type': {
                'TalkID': self.talker,
                'SentenceType': self.sentence_type,
            },
            'Data': OrderedDict({
                'FragmentCnt': self.FragmentCnt,
                'FragmentNum': self.FragmentNum,
                'SeqID': self.SeqID,
                'RadioChannelCode': self.RadioChannelCode,
                'Payload': self.Payload,
                'FillBits': self.FillBits
            })
        }
        return ans
